﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading;
using System.Xml.Serialization;
using Microsoft.Practices.ServiceLocation;
using Sharp.Framework.Logger;
using Timer = System.Timers.Timer;

namespace Sharp.Framework.Services
{
    /// <summary>
    /// 任务管理接口
    /// </summary>
    public class TaskManger
    {
        /// <summary>
        /// 单例对象
        /// </summary>
        private static TaskManger _instance;

        /// <summary>
        /// 排他锁
        /// </summary>
        private static readonly object InstanceLock = new object();


        private readonly IList<TaskRuntime> _tasks;

        /// <summary>
        /// 构造方法
        /// </summary>
        private TaskManger()
        {
            _tasks =new List<TaskRuntime>();
        }

        /// <summary>
        /// 对象实例
        /// </summary>
        /// <returns></returns>
        public static TaskManger Instance()
        {
            lock (InstanceLock)
            {
                if (null == _instance)
                {
                    _instance = new TaskManger();
                }
            }
            return _instance;
        }

        /// <summary>
        /// 将XML字符串反序列化为一个对象
        /// </summary>
        /// <typeparam name="T">对象的类型</typeparam>
        /// <param name="xml">需要反序列化的XML字符串</param>
        /// <returns>对象的实例</returns>
        public static T XmlToObject<T>(string xml) where T : class
        {
            using (var ms = new MemoryStream())
            {
                using (var sr = new StreamWriter(ms, Encoding.UTF8))
                {
                    sr.Write(xml);
                    sr.Flush();
                    ms.Seek(0, SeekOrigin.Begin);
                    var serializer = new XmlSerializer(typeof (T));
                    return serializer.Deserialize(ms) as T;
                }
            }
        }

        /// <summary>
        /// 序列化对象为XML字符串
        /// </summary>
        /// <param name="instance">需要序列化的对象</param>
        /// <returns>对象序列化之后生成的XML字符串</returns>
        public static string ObjectToXml<T>(T instance)
        {
            using (var ms = new MemoryStream())
            {
                var ns = new XmlSerializerNamespaces();

                ns.Add(string.Empty, string.Empty);
                var serializer = new XmlSerializer(typeof (T));
                serializer.Serialize(ms, instance, ns);
                ms.Seek(0, SeekOrigin.Begin);
                using (var reader = new StreamReader(ms, Encoding.UTF8))
                {
                    return reader.ReadToEnd();
                }
            }
        }

        /// <summary>
        /// 任务启动
        /// </summary>
        /// <param name="configPath">配置文件路径</param>
        public void Start(string configPath)
        {
            //任务初始化逻辑
            string taskXml = File.ReadAllText(configPath);
            var config = XmlToObject<TaskConfig>(taskXml);
            foreach (var taskItem in config.Tasks)
            {  
                var task = ServiceLocator.Current.GetInstance<ITask>(taskItem.Class);  
                var taskRuntime = new TaskRuntime(task,taskItem);
                taskRuntime.Start();
                _tasks.Add(taskRuntime);

            }
        }

        /// <summary>
        /// 任务停止
        /// </summary>
        public void Stop()
        {
            foreach (var task in _tasks)
            {
              task.Stop();
            }
        }
    }

    public class TaskRuntime
    {
        public int Number { get; set; }
        public bool IsRuning { get; set; }
        private readonly object _lockObject = new object();

        private readonly ITask _task;
        private readonly Timer _timer;


        public TaskRuntime(ITask task, TaskItem taskItem)
        {
            _task = task;
            var action = new Action(() =>
            {
                try
                {

                    lock (_lockObject)
                    {
                        if (IsRuning && !taskItem.Repeat)
                        {
                            return;
                        }
                         IsRuning = true;
                    }
                    task.Elapsed(new TaskElapsedEventArgs
                    {
                        Number = ++this.Number
                    });
                }
                catch (Exception ex)
                {
                    Log.Error(ex, string.Format("{0}第{1}执行失败", taskItem.Name, Number));
                }
                finally
                {
                    lock (_lockObject)
                    {
                        IsRuning = true;
                    }
                }

            });
            switch (taskItem.Type)
            {
                case 0:
                    _timer = new Timer(taskItem.Interval * 1000);
                    _timer.Elapsed += (sender, e) => action();
                    break;
                case 1:
                    _timer = new Timer(60000);
                    _timer.Elapsed += (sender, e) =>
                    {
                        var now = DateTime.Now;
                        if (now.Hour == taskItem.Hour && now.Minute == taskItem.Minute)
                        {

                            action();
                        }
                    };
                    break;

                case 2:
                    _timer = new Timer(60000);
                    _timer.Elapsed += (sender, e) =>
                    {
                        var now = DateTime.Now;
                        if ((int)now.DayOfWeek == (taskItem.Week - 1) && now.Hour == taskItem.Hour && now.Minute == taskItem.Minute)
                        {
                            action();
                        }
                    };
                    break;

                case 3:
                    _timer = new Timer(60000);
                    _timer.Elapsed += (sender, e) =>
                    {
                        var now = DateTime.Now;
                        if (now.Day == taskItem.Day && (int)now.DayOfWeek == (taskItem.Week - 1) && now.Hour == taskItem.Hour && now.Minute == taskItem.Minute)
                        {
                            action();
                        }
                    };
                    break;
            }


            task.Start(new TaskStartEventArgs
            {
                Name = taskItem.Name,
                Desc = taskItem.Description,
                Paramers = taskItem.Paras.ToDictionary(k => k.Key, v => v.Value)
            });

        }

        public void Stop()
        {
            if (_timer != null)
            {
                _timer.Stop();
            } 
            var wait = new EventWaitHandle(true, EventResetMode.ManualReset);
           _task.Stop(new TaskStopEventArgs { Wait = wait });
            wait.WaitOne();
        }

        public void Start()
        {

            if (_timer != null)
            { 
                _timer.Start();
            }
        }
    }
}